package com.fingard.dsp.bank.directbank.bfb01;

import com.bfb.cap.sdk.SecureUtil;
import com.fingard.constant.Format;
import com.fingard.crypto.SignVerifyHelper;
import com.fingard.dsp.bank.directConfig.ActSetItem;
import com.fingard.dsp.bank.directbank.bankInterface.IStatement;
import com.fingard.dsp.bank.reqrespobj.statement.ReqQryStatement;
import com.fingard.dsp.bank.reqrespobj.statement.RetAtsStatement;
import com.fingard.dsp.bank.reqrespobj.statement.TransState;
import com.fingard.dsp.bank.reqrespobj.statement.detail.RetAtsStatementDetail;
import com.fingard.io.FileHelper;
import com.fingard.text.StringHelper;

import java.security.PublicKey;
import java.util.HashMap;
import java.util.Map;

public class BFB01Statement extends BFB01Base implements IStatement {
    public RetAtsStatement d_Qry_Statement(ReqQryStatement p_reqQrySttm) throws Exception {
        RetAtsStatement retAts = new RetAtsStatement(p_reqQrySttm);
        retAts.writeStart();

        // 获取借记卡快捷支付消费及网关支付日对账单
        String[] smsRecRespHeader = quickPayStatement(p_reqQrySttm, retAts);

        String smsRecTotalNum = retAts.totalNum;
        if ("".equals(smsRecTotalNum)) {
            smsRecTotalNum = "0";
        }

        // 获取代收付平台单笔交易日对账单
        String[] singlePayRecRespHeader = singlePayRecStatement(p_reqQrySttm, retAts);

        String singlePayRecTotalNum = retAts.totalNum;
        if ("".equals(singlePayRecTotalNum)) {
            singlePayRecTotalNum = "0";
        }

        if (smsRecRespHeader[0].equals("-1") && singlePayRecRespHeader[0].equals("-1")) {
            String respInfo = smsRecRespHeader[1];
            if ("".equals(respInfo)) {
                respInfo = singlePayRecRespHeader[1];
            }

            retAts.writeRespCode("-1");
            retAts.writeRespInfo(respInfo);
        } else {
            // 获取成功时写入总笔数
            int totalNum = Integer.parseInt(smsRecTotalNum) + Integer.parseInt(singlePayRecTotalNum);
            retAts.isWritedTotalNum(String.valueOf(totalNum));
        }

        retAts.writeEnd();
        return retAts;
    }

    /**
     * 获取借记卡快捷支付及网关支付消费日对账单
     *
     * @param p_reqQrySttm ATS请求对象
     * @param retAts       ATS返回对象
     * @return String[]{respCode、respInfo}
     */
    private String[] quickPayStatement(ReqQryStatement p_reqQrySttm, RetAtsStatement retAts) throws Exception {
        String[] respHeader = new String[]{"", ""};

        String respCode = "";
        String respInfo = "";

        int totalNum = 0;
        retAts.totalNum = "0";
        
        try {
            ActSetItem actItem = getBankConfig().getActSetItem(p_reqQrySttm.actNum, "*");
            if (actItem == null || !FileHelper.existFile(actItem.ownKeyStorePath)) {
                if (actItem == null) {
                    throw new Exception("未找到账号" + p_reqQrySttm.actNum + "对应的商户配置信息");
                } else {
                    throw new Exception("账号" + p_reqQrySttm.actNum + "对应的商户证书文件不存在");
                }
            }

            // 客户端待签名数据
            HashMap<String, String> signMap = new HashMap<String, String>();
            signMap.put("charset", "00");
            signMap.put("version", "1.0");
            signMap.put("signType", "RSA");
            signMap.put("service", "Statement");
            signMap.put("requestId", getQryTransID());
            signMap.put("merchantId", actItem.merchantId);
            signMap.put("acDate", Format.Date8Format.format(p_reqQrySttm.getBusDate()));

            // 获取HTTP post请求数据
            String reqStr = getHttpPostStr(signMap, actItem);

            // 发送邦付宝并获取返回
            String tmpStrRet[] = sendQuickPay(reqStr);

            // 解析邦付宝返回
            if (tmpStrRet[0].length() == 0) {
                Map<String, String> respMap = getRet(tmpStrRet[1].replace("\"", ""));

                String backRespCode = respMap.get("returnCode");
                if (backRespCode.equals("000000")) {
                    // 服务器签名
                    String respSign = respMap.get("serverSign");
                    byte[] respSignBytes = hexStringToBytes(respSign);

                    // 服务器证书
                    String serverCert = respMap.get("serverCert");
                    PublicKey pubKey = getPublicKey(serverCert);

                    // 验签原始串
                    String respVerifyStr = getVerifyStr(tmpStrRet[1]);
                    WriteBankLogLn2("待验签数据: " + respVerifyStr);

                    // 验签
                    boolean verifyResult = SignVerifyHelper.verifySign(respVerifyStr.getBytes(getCharset()), respSignBytes, pubKey, "SHA1withRSA");

                    // 验签处理
                    if (verifyResult == true) {
                        // 服务器返回对账单文件下载地址
                        String downloadURL = respMap.get("downloadUrl");

                        String url = downloadURL.substring(0, downloadURL.lastIndexOf("/"));
                        downloadURL = downloadURL.replaceAll(url, bankFront.getUrl("quickPay"));

                        // 获取对账单返回内容
                        String[] tmpURLRet = getFileFromURL(downloadURL);

                        if (tmpURLRet[0].length() == 0) {
                            // 对账单内容
                            String tmpDataRet = tmpURLRet[1];
                            WriteBankLogLn2("对账单文件内容: " + tmpDataRet);

                            // 解析对账单数据
                            String[] totalLine = tmpDataRet.split("\n");
                            if (totalLine.length > 1) {
                                String totalInfo = totalLine[0];
                                if (!(totalInfo.indexOf(".") > 0)) {
                                    RetAtsStatementDetail tmpRetDetail = new RetAtsStatementDetail();

                                    totalNum = Integer.parseInt(totalInfo.split("\\|")[0]);

                                    for (int i = 1; i < totalLine.length; i++) {
                                        String[] detailData = totalLine[i].split("\\|");

                                        tmpRetDetail.askNumber = detailData[3];
                                        tmpRetDetail.busTime = detailData[0] + detailData[2];
                                        tmpRetDetail.amount = StringHelper.amountDivide100(detailData[6]);
                                        tmpRetDetail.fee = StringHelper.amountDivide100(detailData[7]);

                                        String transState = detailData[5];
                                        if ("BD".equals(transState)) {
                                            tmpRetDetail.transState = TransState.Success;
                                        } else {
                                            tmpRetDetail.transState = TransState.Fail;
                                        }

                                        retAts.writeRetDetail(tmpRetDetail);
                                    }
                                }
                            } else {
                                respCode = "-1";
                                respInfo = "返回结果不符合预期!";
                            }
                        } else {
                            respCode = "-1";
                            respInfo = tmpURLRet[1];
                        }
                    } else {
                        respCode = "-1";
                        respInfo = "验证签名失败！";
                    }
                } else {
                    respCode = "-1";
                    respInfo = respMap.get("returnMessage");
                }
            } else {
                respCode = "-1";
                respInfo = tmpStrRet[1];
            }
        } catch (Exception e) {
            respCode = "-1";
            respInfo = e.getMessage();
            WriteBankLogLn(e);
        }
        
        retAts.totalNum = String.valueOf(totalNum);

        respHeader[0] = respCode;
        respHeader[1] = respInfo;

        return respHeader;
    }

    /**
     * 获取代收付平台单笔日对账单
     * <p>
     * --可获取以下种类对账单：
     * 1、单笔实时代扣
     * 2、单笔实时代付
     * 3、单笔非实时付款(闪付)
     *
     * @param p_reqQrySttm ATS请求对象
     * @param retAts       ATS响应对象
     * @return String[]{respCode、respInfo}
     */
    private String[] singlePayRecStatement(ReqQryStatement p_reqQrySttm, RetAtsStatement retAts) throws Exception {
        String[] respHeader = new String[]{"", ""};

        String respCode = "";
        String respInfo = "";
        
        int totalNum = 0;
        retAts.totalNum = "0";

        try {
            ActSetItem actItem = getBankConfig().getActSetItem(p_reqQrySttm.actNum, "*");
            if (actItem == null || !FileHelper.existFile(actItem.ownKeyStorePath)) {
                if (actItem == null) {
                    throw new Exception("未找到账号" + p_reqQrySttm.actNum + "对应的商户配置信息");
                } else {
                    throw new Exception("账号" + p_reqQrySttm.actNum + "对应的商户证书文件不存在");
                }
            }

            // 待签名数据
            HashMap<String, String> signMap = new HashMap<String, String>();

            signMap.put("version", "1.0");
            signMap.put("transCode", "settlement");
            signMap.put("signType", "RSA");
            signMap.put("merchantId", actItem.merchantId);
            signMap.put("txnDate", Format.Date8Format.format(p_reqQrySttm.getBusDate()));

			/* 00: 单笔    01:全部(批量和单笔)*/
            signMap.put("checkType", "00");

            // 发送邦付宝
            String[] tmpStrRet = sendToBank(signMap, actItem);

            // 解析邦付宝返回
            if (tmpStrRet[0].length() == 0) {
                Map<String, String> map = getRet(tmpStrRet[1]);

                if (map.size() > 0) {
                    // 受理成功
                    String backCode = map.get("respCode");
                    if (backCode.equals("B0")) {
                    	totalNum = Integer.parseInt(map.get("succQty"));

                        // 获取对账文件密文
                        String fileContent = map.get("fileContent");

                        // 解密文件内容
                        byte[] backStatementBytes = SecureUtil.inflater(SecureUtil.base64Decode(fileContent.getBytes(getCharset())));
                        String backStatement = new String(backStatementBytes, getCharset());

                        WriteBankLogLn2("单笔对账单返回数据为: " + backStatement);

                        // 解析单笔对账单数据
                        String backRespInfo[] = backStatement.split("\n");
                        for (int i = 0; i < backRespInfo.length; i++) {
                            RetAtsStatementDetail tmpRetDetail = new RetAtsStatementDetail();

                            tmpRetDetail.askNumber = backRespInfo[i].substring(0, 64).trim();
                            tmpRetDetail.busTime = String.format("%-14s", backRespInfo[i].substring(149, 157)).replace(" ", "0");
                            tmpRetDetail.amount = StringHelper.amountDivide100(convertMoney(backRespInfo[i].substring(158, 176)));
                            tmpRetDetail.fee = StringHelper.amountDivide100(convertMoney(backRespInfo[i].substring(219, 231)));

                            String state = backRespInfo[i].substring(232, 234).trim();
                            if (state.equals("S")) {
                                tmpRetDetail.transState = TransState.Success;
                            } else if (state.equals("J")) {
                                tmpRetDetail.transState = TransState.ToRefund;
                            } else {
                                tmpRetDetail.transState = TransState.Exception;
                            }

                            retAts.writeRetDetail(tmpRetDetail);
                        }
                    } else {
                        respCode = "-1";
                        respInfo = map.get("respMsg");
                    }
                } else {
                    respCode = "-1";
                    respInfo = "返回数据格式错误!";
                }
            } else {
                respCode = "-1";
                respInfo = tmpStrRet[1];
            }
        } catch (Exception e) {
            respCode = "-1";
            respInfo = e.getMessage();
            WriteBankLogLn(e);
        }
        
        retAts.totalNum = String.valueOf(totalNum);

        respHeader[0] = respCode;
        respHeader[1] = respInfo;

        return respHeader;
    }
}
